#include "plot.h"
#include "ui_plot.h"
#include <QDebug>

Plot::Plot(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Plot)
{
    ui->setupUi(this);
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));
    setupPlot();

    // create connection between axes and scroll bars:
    connect(ui->scrollBarHori, SIGNAL(valueChanged(int)), this, SLOT(horzScrollBarChanged(int)));
    connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange)));
    connect(ui->lineEditNum,SIGNAL(editingFinished()),this,SLOT(xTimeScaleChange()));
    connect(ui->pushButtonOK,SIGNAL(clicked(bool)),this,SLOT(startPaint()));
    connect(ui->pushButtonClear,SIGNAL(clicked(bool)),this,SLOT(clearPaint()));
    connect(ui->pushButtonOpen,SIGNAL(clicked(bool)),this,SLOT(openPlotFile()));
    connect(ui->pushButtonSave,SIGNAL(clicked(bool)),this,SLOT(savePlotFile()));
}

Plot::~Plot()
{
    delete iniFile;
    delete dataTimer;
    delete sysTime;
    if(graghName.size())delete []checkBoxGragh;
    delete ui;
}

void Plot::setupPlot()
{
    status = false;
    iniFile = new minIni("config.ini");
    uint i=0,j=0;
    string section,key;
    while((section=iniFile->getsection(i++))!=""){
        if(section=="paint_name")
            while((key=iniFile->getkey(section,j++))!=""){
                graghName.push_back(key);
            }
    }
    if(graghName.size())checkBoxGragh = new QCheckBox[graghName.size()];
    for(i=0;i<graghName.size();i++){
        double offset = iniFile->getd("paint_offset",graghName[i]);
        graghOffset.push_back(offset);
        double scale = iniFile->getd("paint_scale",graghName[i],1.0);
        graghScale.push_back(scale);
        ui->horizontalLayout2->addWidget(&checkBoxGragh[i]);
        checkBoxGragh[i].setText(graghName[i].c_str());
        checkBoxGragh[i].setChecked(true);
        Qt::GlobalColor color;
        switch(iniFile->geti("paint_name",graghName[i])){
        case 0:color=Qt::red;break;
        case 1:color=Qt::green;break;
        case 2:color=Qt::blue;break;
        case 3:color=Qt::cyan;break;
        case 4:color=Qt::magenta;break;
        case 5:color=Qt::yellow;break;
        default:color=Qt::black;break;
        }
        ui->customPlot->addGraph();
        ui->customPlot->graph(i)->setPen(QPen(color));
//        ui->customPlot->graph(i)->setBrush(QBrush(QColor(0, 0, 255, 20)));
        ui->customPlot->graph(i)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 3));
        connect(&checkBoxGragh[i],SIGNAL(toggled(bool)),this,SLOT(setGraghVisible(bool)));
    }
    xTimeScaleChange();
    xAxisChanged(ui->customPlot->xAxis->range());

    // The following plot setup is mostly taken from the plot demos:
    ui->customPlot->axisRect()->setupFullAxesBox(true);
    ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
    ui->customPlot->yAxis->grid()->setSubGridVisible(true);
    ui->customPlot->xAxis->grid()->setSubGridVisible(true);
    ui->customPlot->yAxis->setScaleType(QCPAxis::stLinear);
    ui->customPlot->yAxis2->setScaleType(QCPAxis::stLinear); //QCPAxis::stLogarithmic
    //ui->customPlot->yAxis->setNumberFormat("eb"); // e = exponential, b = beautiful decimal powers
    //ui->customPlot->xAxis->setNumberPrecision(0); // makes sure "1*10^4" is displayed only as "10^4"

    ui->customPlot->xAxis->setRange(0,xTimeScale);
    ui->customPlot->yAxis->setRange(-10, 10);

    sysTime = new QTime(QTime::currentTime());
    dataTimer = new QTimer;
    timeBase = 0;

    connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange)));
    connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange)));

    // setup a timer that repeatedly calls MainWindow::realtimeDataSlot:
    connect(dataTimer, SIGNAL(timeout()), this, SLOT(autoGenerateData()));
}

void Plot::startPaint()
{
    if(ui->pushButtonOK->text()=="OK"){
        status = true;
        ui->pushButtonOK->setText("NO");
        timeBase = sysTime->elapsed()/1000.0-timeBase;
        pointNum = 0;
        dataTimer->start(100); // Interval 0 means to refresh as fast as possible
    }
    else{
        status = false;
        ui->pushButtonOK->setText("OK");
        timeBase = sysTime->elapsed()/1000.0-timeBase;
        dataTimer->stop(); // Interval 0 means to refresh as fast as possible
    }
}

void Plot::clearPaint()
{
    if(!status)timeBase = 0;
    else timeBase = sysTime->elapsed()/1000.0;
    pointNum = 0;
    for(uint i=0;i<graghName.size();i++)
        ui->customPlot->graph(i)->data()->clear();
    ui->customPlot->replot();
}

void Plot::horzScrollBarChanged(int value)
{
    static int lastValue = 0;
    if(status==false){
        ui->customPlot->xAxis->setRange(ui->customPlot->xAxis->range().upper+(value-lastValue)/100.0, xTimeScale, Qt::AlignRight);
        ui->customPlot->replot();
    }
    lastValue = value;
}

void Plot::xAxisChanged(QCPRange range)
{
    if(status){
        int value = qRound(range.upper*100.0);
        if(value>MAX_PAGE*xTimeScale*100)value = MAX_PAGE*xTimeScale*100;
        ui->scrollBarHori->setValue(value); // adjust position of scroll bar slider
    }
}

void Plot::xTimeScaleChange(){
    xTimeScale = ui->lineEditNum->text().toInt();
    if(xTimeScale<0.05){
        xTimeScale=0.05;
        ui->lineEditNum->setText("0.05");
    }
    ui->scrollBarHori->setPageStep(xTimeScale*100);
    ui->scrollBarHori->setRange(0, MAX_PAGE*xTimeScale*100);
    if(!status){
        ui->customPlot->xAxis->setRange(0, xTimeScale);
        ui->customPlot->replot();
    }
}

void Plot::autoGenerateData(){
    double time = sysTime->elapsed()/1000.0-timeBase;
    vector<double> v;
    v.push_back(time);
    for(uint i=0;i<graghName.size();i++){
        double ydata=qSin(time)*3+2*qrand()/(double)RAND_MAX*qSin(time/0.3843);
        v.push_back(ydata);
    }
    realtimeDataSlot(v);
}

void Plot::realtimeDataSlot(vector<double> &v) //v[0]:x other:y
{
    if(v.size()<2)return;
    uint lineNum = graghName.size();
    if(v.size()<=graghName.size())lineNum = v.size()-1;
    for(uint i=0;i<lineNum;i++)
        ui->customPlot->graph(i)->addData(v[0], (v[i+1]-graghOffset[i])*graghScale[i]);
    if(v[0]>xTimeScale)ui->customPlot->xAxis->setRange(v[0], xTimeScale, Qt::AlignRight);
    else ui->customPlot->xAxis->setRange(0, xTimeScale);
    ui->customPlot->replot();

    pointNum++;
    static long int lastPointNum = 0;
    if(pointNum<lastPointNum)lastPointNum=0;
    static double lastTime = 0;
    double curTime = sysTime->elapsed()/1000.0;
    if (curTime - lastTime >= 2) // average fps over 2 seconds
    {
        QString data = QString("%1 FPS, Total Data points: %2")
                .arg((pointNum-lastPointNum)/2) .arg(pointNum);
        ui->labelStatus->setText(data);
        lastPointNum = pointNum;
        lastTime = curTime;
    }
}

void Plot::setGraghVisible(bool status){
    for(uint i=0;i<graghName.size();i++)
        ui->customPlot->graph(i)->setVisible(checkBoxGragh[i].isChecked());
    ui->customPlot->replot();
}

void Plot::savePlotFile(){
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"));
    if(fileName.size()){
        QFile f(fileName);
        if(!f.open(QIODevice::WriteOnly | QIODevice::Text)){
            cout << "Open failed." << endl;
            return;
        }
        QTextStream out(&f);
        for(int i=0;i<ui->customPlot->graph(0)->data()->size();i++){
            for(uint j=0;j<graghName.size();j++){
                out<<ui->customPlot->graph(j)->dataMainValue(i)<<"\t";
            }
            out<<endl;
        }
        f.close();
    }
}

void Plot::openPlotFile(){
    QString fileName = QFileDialog::getOpenFileName(this, tr("Read File"));
    if(fileName.size()){
        QFile f(fileName);
        if(!f.open(QIODevice::ReadOnly | QIODevice::Text)){
            cout << "Open failed." << endl;
            return;
        }
        for(uint i=0;i<graghName.size();i++)
            ui->customPlot->graph(i)->data()->clear();
        QTextStream in(&f);
        int lineNum = -1;
        while(!in.atEnd())
        {
            stringstream ss(in.readLine().toStdString());
            lineNum++;
            for(uint i=0;i<graghName.size();i++){
                double data;
                ss >> data;
                ui->customPlot->graph(i)->addData(lineNum,data);
            }
        }
        ui->customPlot->replot();
        f.close();
    }
}
